require 'levenshtein'
require 'nokogiri'
require 'open-uri'

module SteamWishlistChecker
  class Checker
    attr_reader :steam_id, :check

    def initialize(steam_id, check)
      @steam_id = steam_id
      @url = (@steam_id =~ /\A\d+\z/ && @steam_id.length == '76561198002350807'.length) ? 'profiles' : 'id'
      @check = check
    end

    def results
      @results ||= wishlist && compare_lists
    end

    def wishlist
      @wishlist ||= fetch_wishlist
    end

    private

      def fetch_wishlist
        begin
          doc = Nokogiri::HTML(open("https://steamcommunity.com/#{@url}/#{@steam_id}/wishlist"))
          @wishlist = doc.css('h4.ellipsis').map(&:text)
        rescue SocketError
          raise SocketError, 'It seems you do not have an Internet connection.'
        end

        if @wishlist.empty?
          error = doc.css('div.error_ctn')
          if error.any?
            fail 'Profile could not be found. Please check the SteamID.'
          else
            fail 'This wishlist is empty or its visibility is set to "friends only" or "private".'
          end
        end
        @wishlist
      end

      def compare_lists
        results = @check.each_with_object([]) do |game, res|
          @wishlist.each_with_index do |wish, index|
            # if looking for "Evoland" do not push "Evoland 2" and the other way round
            # either both entries do not have a number or the number is equal
            if res.none? { |entry| entry.has_value?(game) } &&
                Levenshtein.distance(wish.downcase, game.downcase) < Math.sqrt(wish.length) &&
                ((game.scan(/\d+$/).empty? && wish.scan(/\d+$/).empty?) ||
                (game.scan(/\d+$/).any? && game.scan(/\d+$/).first == wish.scan(/\d+$/).first))
              res << { name: wish, index: index + 1 }
              break
            end
          end
        end
        results.sort_by { |res| res[:index] }
      end
  end
end
